package com.gk.panda.apis.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gk.panda.apis.Vo.exports.ExportBiologyVO;
import com.gk.panda.apis.dto.BiologyPointSaveDto;
import com.gk.panda.apis.dto.BiologyPointSearchDto;
import com.gk.panda.apis.dto.BiologyPointSortDto;
import com.gk.panda.apis.dto.imports.ImportBiologyDTO;
import com.gk.panda.apis.mapper.BiologyPointMapper;
import com.gk.panda.apis.service.BiodiversityService;
import com.gk.panda.apis.service.BiologyPointService;
import com.gk.panda.apis.service.DictionaryService;
import com.gk.panda.apis.util.ListCopyUtils;
import com.gk.panda.apis.util.excel.ExcelUtils;
import com.gk.panda.commons.exception.ServerException;
import com.gk.panda.commons.util.UserUtil;
import com.gk.panda.pojo.Biodiversity;
import com.gk.panda.pojo.BiologyPoint;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class BiologyPointServiceImpl extends ServiceImpl<BiologyPointMapper, BiologyPoint> implements BiologyPointService {

    private static final String TEMPLATE_FILE_NAME = "动植物导入模板.xlsx";
    private static final String FILE_SUFFIX = ".xlsx";

    @Autowired
    private BiodiversityService biodiversityService;

    @Autowired
    private DictionaryService dictionaryService;

    /**
     * 添加动植物点位
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addBiologyPoint(BiologyPointSaveDto dto) {
        BiologyPoint biologyPoint = new BiologyPoint();
        String geoJsonStart = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":[";
        String geoJsonEnd = "]},\"properties\":{\"type\":\"动植物点位\"}}";
        StringBuffer buffer = new StringBuffer();
        for (String[] place : dto.getPlace()) {
            buffer.append("[").append(place[0]).append(",").append(place[1]).append("],");
        }
        String str = buffer.toString();
        String geoJsonMid = str.substring(0, str.length() - 1);
        String geoJson = geoJsonStart + geoJsonMid + geoJsonEnd;
        biologyPoint.setGeoJson(geoJson);
        if (StringUtils.isNotEmpty(dto.getIcon())) {
            biologyPoint.setIcon(dto.getIcon());
        } else {
            biologyPoint.setIcon(dto.getKingdom() == 0 ? dictionaryService.getValue("animal_icon") : dictionaryService.getValue("plant_icon"));
        }
        biologyPoint.setPicUrl(dto.getPicUrl());
        biologyPoint.setKingdom(dto.getKingdom());
        biologyPoint.setBioId(dto.getBioId());
        biologyPoint.setName(dto.getName());
        biologyPoint.setProtectionLevel(dto.getProtectionLevel());
        biologyPoint.setCreator(UserUtil.getCurrentUser());
        BiologyPoint one = getOne(Wrappers.<BiologyPoint>lambdaQuery().orderByDesc(BiologyPoint::getSort).last("limit 1"));
        biologyPoint.setSort(one.getSort() + 1);
        return this.save(biologyPoint);
//        save(biologyPoint);
//        for (String[] place : dto.getPlace()) {
//            BioPointResource BPResource = new BioPointResource();
//            BPResource.setLot(place[0]);
//            BPResource.setLat(place[1]);
//            BPResource.setBiologyName(dto.getName());
////            BPResource.setPath(dto.getPicUrl());
//            BPResource.setBioPointId(biologyPoint.getId());
//        }
//        return true;
    }

    /**
     * 分页查询动植物点位（包括geoJson数据）
     *
     * @param dto
     * @return
     */
    @Override
    public Page<BiologyPoint> getBiologyPointList(BiologyPointSearchDto dto) {
        QueryWrapper<BiologyPoint> wrapper = new QueryWrapper<>();
        Page<BiologyPoint> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        wrapper.eq(StringUtils.isNotEmpty(dto.getName()), "name", dto.getName());
        wrapper.in(CollectionUtils.isNotEmpty(dto.getKingdoms()), "kingdom", dto.getKingdoms());
        wrapper.in(CollectionUtils.isNotEmpty(dto.getProtectionLevels()), "protection_level", dto.getProtectionLevels());
        wrapper.orderByDesc("sort").orderByDesc("create_time");
        return this.page(page, wrapper);
    }

    /**
     * 根据id查询动植物点位详情
     *
     * @param id
     * @return
     */
    @Override
    public BiologyPoint getBiologyPointDetails(Integer id) {
        return this.getById(id);
    }

    /**
     * 修改动植物点位
     *
     * @param dto
     * @return
     */
    @Override
    public boolean updateBP(BiologyPointSaveDto dto) {
        BiologyPoint biologyPoint = new BiologyPoint();
        String geoJsonStart = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":[";
        String geoJsonEnd = "]},\"properties\":{\"type\":\"动植物点位\"}}";
        StringBuffer buffer = new StringBuffer();
        for (String[] place : dto.getPlace()) {
            buffer.append("[").append(place[0]).append(",").append(place[1]).append("],");
        }
        String str = buffer.toString();
        String geoJsonMid = str.substring(0, str.length() - 1);
        String geoJson = geoJsonStart + geoJsonMid + geoJsonEnd;
        return update(Wrappers.<BiologyPoint>lambdaUpdate().eq(BiologyPoint::getId,dto.getId())
        .set(BiologyPoint::getGeoJson,geoJson)
//        .set(BiologyPoint::getIcon,dto.getIcon())
        .set(BiologyPoint::getKingdom,dto.getKingdom())
        .set(BiologyPoint::getName,dto.getName())
        .set(BiologyPoint::getPicUrl,dto.getPicUrl())
        .set(BiologyPoint::getBioId,dto.getBioId())
        .set(BiologyPoint::getProtectionLevel,dto.getProtectionLevel())
        .set(BiologyPoint::getModifier,UserUtil.getCurrentUser())
        );
//        biologyPoint.setId(dto.getId());
//        biologyPoint.setGeoJson(geoJson);
//        biologyPoint.setIcon(dto.getIcon());
//        biologyPoint.setKingdom(dto.getKingdom());
//        biologyPoint.setName(dto.getName());
//        biologyPoint.setPicUrl(dto.getPicUrl());
//        biologyPoint.setProtectionLevel(dto.getProtectionLevel());
//        biologyPoint.setModifier(UserUtil.getCurrentUser());
//        return this.updateById(biologyPoint);
    }

    /**
     * 下载动植物导入模板
     *
     * @param response P
     */
    @Override
    public void downloadTemplate(HttpServletResponse response) {
        XSSFWorkbook workbook = getWorkbook();
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 保护等级
        String[] protectionLevel = {"Ⅰ", "Ⅱ", "Ⅲ"};
        ExcelUtils.setDropDownBox(1, 65535, 1, 1, sheet, protectionLevel);
        // 类型
        String[] kingdom = {"动物", "植物"};
        ExcelUtils.setDropDownBox(1, 65535, 2, 2, sheet, kingdom);

        // 生成文件
        String downloadFileName = "动植物信息" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 批量导入动植物信息
     *
     * @param file P
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importBiology(MultipartFile file) {
        InputStream inputStream;
        List<ImportBiologyDTO> resultList;
        try {
            inputStream = file.getInputStream();
            ImportParams params = new ImportParams();
            params.setStartSheetIndex(0);
            params.setSheetNum(1);
            params.setTitleRows(0);
            params.setHeadRows(1);
            resultList = ExcelImportUtil.importExcel(inputStream, ImportBiologyDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        String geoJsonStart = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":[";
        String geoJsonEnd = "]},\"properties\":{\"type\":\"动植物点位\"}}";
        String separate = "-";
        String currentUser = UserUtil.getCurrentUser();
        for (ImportBiologyDTO k : resultList) {
            if (StringUtils.isNotBlank(k.getKingdomName())) {
                // 因为只有动植物，所以没有写枚举，如果填写其他统统是“植物”
                Integer kingdom = "动物".equals(k.getKingdomName()) ? 0 : 1;
                k.setKingdom(kingdom);
            }
            // 处理经纬度
            if (StringUtils.isNotBlank(k.getLotAndLat())) {
                String[] split = k.getLotAndLat().split(separate);
                StringBuilder builder = new StringBuilder();
                for (String v : split) {
                    builder.append("[").append(v).append("],");
                }
                String str = builder.toString();
                String geoJsonMid = str.substring(0, str.length() - 1);
                String geoJson = geoJsonStart + geoJsonMid + geoJsonEnd;
                k.setGeoJson(geoJson);
            }
            k.setCreator(currentUser);
        }
        List<BiologyPoint> biologyPoints = ListCopyUtils.copyListProperties(resultList, BiologyPoint::new);
        List<String> names = resultList.stream().map(ImportBiologyDTO::getName).collect(Collectors.toList());
        List<Biodiversity> biodiversities = biodiversityService.list(Wrappers.<Biodiversity>lambdaQuery().in(Biodiversity::getSpecies, names));
        BiologyPoint one = getOne(Wrappers.<BiologyPoint>lambdaQuery().orderByDesc(BiologyPoint::getSort).last("limit 1"));
        for (int i = 0; i < biologyPoints.size(); i++) {
            BiologyPoint k = biologyPoints.get(i);
            for (Biodiversity v : biodiversities) {
                if (v.getSpecies().equals(k.getName())) {
                    k.setBioId(v.getId());
                }
            }
            if (k.getBioId() == null) return "不能导入生物名录中不存在的物种：" + k.getName();
            k.setSort(one.getSort() + 1 + i);
        }
        saveBatch(biologyPoints);
        return "success";
    }

    /**
     * 批量导出动植物信息
     *
     * @param response P
     */
    @Override
    public void exportBiology(HttpServletResponse response) {
        List<BiologyPoint> biologyPoints = list(Wrappers.<BiologyPoint>lambdaQuery().orderByDesc(BiologyPoint::getCreateTime));
        if (CollectionUtils.isEmpty(biologyPoints)) {
            throw new ServerException("暂无数据导出！");
        }
        List<ExportBiologyVO> vos = ListCopyUtils.copyListProperties(biologyPoints, ExportBiologyVO::new);
        vos.forEach(k -> {
            if (k.getKingdom() != null) {
                String name = k.getKingdom().equals(0) ? "动物" : "植物";
                k.setKingdomName(name);
            }
            String geoJson = k.getGeoJson();
            int begin = geoJson.indexOf("[");
            int end = geoJson.lastIndexOf("]");
            String substring = geoJson.substring(begin, end + 1);
            String replace = substring.replace("],[", "-").replace("[[", "").replace("]]", "");
            k.setLotAndLat(replace);
        });
        // 导出
        ExportParams params = new ExportParams();
        params.setSheetName("动植物信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportBiologyVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = "动植物导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    @Override
    public void updateSort(BiologyPointSortDto dto) {
//        QueryWrapper<BiologyPoint> wrapper = new QueryWrapper<>();
//        wrapper.in(dto.getKingdoms() != null && dto.getKingdoms().size() > 0,"kingdom",dto.getKingdoms());
//        wrapper.orderByDesc("sort").last("limit " + (dto.getSort()-1) + ",1");
//        BiologyPoint bp = getOne(wrapper);
//        UpdateWrapper<BiologyPoint> updateWrapper = new UpdateWrapper<>();
//        updateWrapper.clear();
//        updateWrapper.eq("id",dto.getId()).set("sort",bp.getSort()+1);
//        update(updateWrapper);
        BiologyPoint point = getById(dto.getId());
        QueryWrapper<BiologyPoint> wrapper = new QueryWrapper<>();
        wrapper.in(dto.getKingdoms() != null && dto.getKingdoms().size() > 0, "kingdom", dto.getKingdoms());
        wrapper.orderByDesc("sort").last("limit " + (dto.getSort() - 1) + ",1");
        BiologyPoint bp = getOne(wrapper);
        int num = point.getSort() - bp.getSort();
        if (num == 0) {
            throw new ServerException("与原排序位置相同");
        }
        List<BiologyPoint> list = list(Wrappers.<BiologyPoint>lambdaQuery().orderByDesc(BiologyPoint::getSort).last("limit " + (dto.getSort() - 1) + "," + Math.abs(num)));
        point.setSort(bp.getSort());
        updateById(point);
        if (num < 0) {
            list.forEach(biologyPoint -> {
                biologyPoint.setSort(biologyPoint.getSort() - 1);
            });
            updateBatchById(list);
        } else if (num > 0) {
            list.forEach(biologyPoint -> {
                biologyPoint.setSort(biologyPoint.getSort() + 1);
            });
            updateBatchById(list);
        }
//        UpdateWrapper<BiologyPoint> updateWrapper = new UpdateWrapper<>();
//        updateWrapper.clear();
//        updateWrapper.eq("id",dto.getId()).set("sort",bp.getSort()+1);
//        update(updateWrapper);
    }

    @Override
    public List<BiologyPoint> getBioPointListForLS(BiologyPointSearchDto dto) {
        QueryWrapper<BiologyPoint> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(dto.getName()), "name", dto.getName());
        wrapper.in(CollectionUtils.isNotEmpty(dto.getKingdoms()), "kingdom", dto.getKingdoms());
        wrapper.in(CollectionUtils.isNotEmpty(dto.getProtectionLevels()), "protection_level", dto.getProtectionLevels());
        wrapper.orderByDesc("sort").orderByDesc("create_time");
        List<BiologyPoint> list = this.list(wrapper);
        String geoJsonStart = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPoint\",\"coordinates\":";
        String geoJsonEnd = "},\"properties\":{\"type\":\"动植物点位\"}}";
        List<BiologyPoint> bps = new ArrayList<>();
        list.forEach(biologyPoint -> {
            String geoJson = biologyPoint.getGeoJson();
            String str = geoJson.replace(geoJsonStart, "").replace(geoJsonEnd, "");
            List coordinates = JSON.parseObject(str, List.class);
            for (Object s : coordinates) {
                BiologyPoint point = new BiologyPoint();
                BeanUtils.copyProperties(biologyPoint, point);
                point.setGeoJson(geoJsonStart + "[" + s.toString() + "]" + geoJsonEnd);
                bps.add(point);
            }
        });
        return bps;
    }

    /**
     * 获取workbook
     *
     * @return XSSFWorkbook
     */
    private XSSFWorkbook getWorkbook() {
        InputStream inputStream;
        XSSFWorkbook workbook;
        try {
            ClassPathResource classPathResource = new ClassPathResource("excels/" + TEMPLATE_FILE_NAME);
            inputStream = classPathResource.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
        } catch (IOException e) {
            throw new ServerException("动植物导入模板获取异常！");
        }
        return workbook;
    }


    public static void main(String[] args) {
        String str = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[[1,1],[1,1]]},\"properties\":{\"type\":\"动植物点位\"}}";
//        GeoJsonVO parse = (GeoJsonVO) JSONObject.parse(str);
//        System.out.println(parse);
        int i = str.split("]").length - 1;
        int begin = str.indexOf("[");
        int end = str.lastIndexOf("]");
        String substring = str.substring(begin, end + 1);
        String replace = substring.replace("],[", "-").replace("[[", "").replace("]]", "");
        System.out.println(i);
        System.out.println(replace);


    }
}
